#include <xconfig.h>
#if CONFIG_WINDOWS
	#include <WinSock2.h>
#elif CONFIG_LINUX
	#include <sys/socket.h>
	#include <sys/types.h>
	#include <sys/stat.h>
	#include <netinet/in.h>
	#include <netdb.h>
	#include <sys/wait.h>
	#include <arpa/inet.h>
	#include <errno.h>
	#include <fcntl.h>
	#include <unistd.h>
#endif
#if CONFIG_BCB
    #pragma hdrstop
#endif
#include "xsocketapi.h"
namespace zdh
{
	void XSocketAPI::SocketInit()
	{
		#if CONFIG_WINDOWS
			WSADATA aWSAData;
			WSAStartup( 0x0202, &aWSAData );
		#endif
	}
	
	void XSocketAPI::SocketClose()
	{
		#if CONFIG_WINDOWS
			WSACleanup();
		#endif
	}

	XSOCKET_HANDLE XSocketAPI::Socket(int aDomain,int aType,int aProtocol)
	{
		return socket(aDomain,aType,aProtocol);
	}

	int XSocketAPI::Close(XSOCKET_HANDLE aSockfd)
	{
		#if CONFIG_WINDOWS
			return closesocket(aSockfd);
		#elif CONFIG_LINUX
			return close(aSockfd);
		#endif
	}

	int XSocketAPI::ShutDown(XSOCKET_HANDLE aSockfd,int aHow)
	{
		return shutdown(aSockfd,aHow);
	}

	XSSize XSocketAPI::SendTo(XSOCKET_HANDLE aSockfd,const char * buf,XSize nbytes,int flags,const struct sockaddr * to,XSocklen tolen)
	{
		return sendto(aSockfd,buf,nbytes,flags,to,tolen);
	}

	XSSize XSocketAPI::Send(XSOCKET_HANDLE aSockfd,const char * buf,XSize nBytes,int flags)
	{
		return send(aSockfd,buf,nBytes,flags);
	}
	XSSize XSocketAPI::RecvFrom(XSOCKET_HANDLE aSockfd,char * buf,XSize len,int flags,struct sockaddr * addr,XSocklen * addrlen)
	{
		return recvfrom(aSockfd,buf,len,flags,addr,addrlen);
	}
	
	XSSize XSocketAPI::Recv(XSOCKET_HANDLE aSockfd,char * buff,XSize nbytes,int flags)
	{
		return recv(aSockfd,buff,nbytes,flags);
	}

	int XSocketAPI::Bind(XSOCKET_HANDLE aSockfd,const struct sockaddr * name,XSocklen namelen)
	{
		return bind(aSockfd,name,namelen);
	}
	
	int XSocketAPI::Listen(XSOCKET_HANDLE aSockfd,int backlog)
	{
		return listen(aSockfd,backlog);
	}

	int XSocketAPI::Connect(XSOCKET_HANDLE aSockfd,const struct sockaddr * addr,XSocklen len)
	{
		return connect(aSockfd,addr,len);
	}

	XSOCKET_HANDLE XSocketAPI::Accept(XSOCKET_HANDLE aSockfd,struct sockaddr * addr,XSocklen * len)
	{
		return accept(aSockfd,addr,len);
	}

	int XSocketAPI::GetHostName(char * name,int namelen)
	{
		return gethostname(name,namelen);
	}

	struct hostent * XSocketAPI::GetHostByName(char * name)
	{
		return gethostbyname(name);
	}

	struct hostent * XSocketAPI::GetHostByAddr(const char * addr,int len,int type)
	{
		return gethostbyaddr(addr,len,type);
	}

	int XSocketAPI::GetSockName(XSOCKET_HANDLE aSockfd,struct sockaddr * addr,XSocklen * len)
	{
		return getsockname(aSockfd,addr,len);
	}

	int XSocketAPI::GetPeerName(XSOCKET_HANDLE aSockfd,struct sockaddr * addr,XSocklen * len)
	{
		return getpeername(aSockfd,addr,len);
	}

	int XSocketAPI::Select(XSOCKET_HANDLE nfds,fd_set * readfds,fd_set * writefds,fd_set * exceptfds, struct timeval * timeout)
	{
		#if CONFIG_WINDOWS
			return select(0,readfds,writefds,exceptfds,timeout);
		#elif CONFIG_LINUX
			return select(nfds,readfds,writefds,exceptfds,timeout);
		#endif
	}
	XU32 XSocketAPI::HostToNetworkLong(XU32 hostint32)  
	{
		return htonl(hostint32);
	}

	XU16 XSocketAPI::HostToNetworkShort(XU16 hostint16)
	{
		return htons(hostint16);
	}

	XU32 XSocketAPI::NetworkToHostLong(XU32 netint32) 
	{
		return ntohl(netint32);
	}

	XU16 XSocketAPI::NetworkToHostShort(XU16 netint16) 
	{
		return ntohs(netint16);
	}

	const char * XSocketAPI::INet_ntoa(XU32 aAddr)
	{
		struct in_addr v;
		v.s_addr = aAddr;
		return inet_ntoa(v);
	}

	XU32 XSocketAPI::INet_addr(const char * aAddr)
	{
		return inet_addr(aAddr);
	}

	int XSocketAPI::SetSockOpt(XSOCKET_HANDLE aSockfd,int aLevel,int aOption,const char * aVal,XSocklen aLen)
	{
		return setsockopt(aSockfd,aLevel,aOption,aVal,aLen);
	}

	int XSocketAPI::GetSockOpt(XSOCKET_HANDLE aSockfd,int aLevel,int aOption,char * aVal,XSocklen * aLen)
	{
		return getsockopt(aSockfd,aLevel,aOption,aVal,aLen);
	}
	int XSocketAPI::GetErrorNo()
	{
		#if CONFIG_WINDOWS
			return WSAGetLastError();
		#elif CONFIG_LINUX
			return errno;
		#endif
	}
	int XSocketAPI::SetBlockStatus(XSOCKET_HANDLE aSockfd,bool aBlockFlag)
	{
		#if CONFIG_WINDOWS
			if( aBlockFlag )
			{
				XU32 mode = 0;
				return ioctlsocket(aSockfd,FIONBIO,&mode);
			}
			else
			{
				XU32 mode = 1;
				return ioctlsocket(aSockfd,FIONBIO,&mode);
			}
		#elif CONFIG_LINUX
			if( aBlockFlag )
			{
				int val = fcntl(aSockfd, F_GETFL, 0);
				if( val != -1 ) 
				{
					val=val & (0xffffffff^O_NONBLOCK);
					val = fcntl(aSockfd, F_SETFL, val);
				}
				return val;
			}
			else
			{
				int val = fcntl(aSockfd, F_GETFL, 0);

				if( val != -1 ) 
				{
					val = val | O_NONBLOCK;
					val = fcntl(aSockfd,F_SETFL, val);
				}
				return val;

			}
		#endif
	}
}

